package service

import (
	"context"
	"fmt"
	"github.com/LyricTian/captcha"
	"github.com/gin-gonic/gin"
	"go-admin-server/app/dao/model"
	"go-admin-server/app/dao/repo"
	"go-admin-server/app/dao/repository"
	"go-admin-server/app/dto"
	"go-admin-server/common/errors"
	"go-admin-server/common/utils"
	"go-admin-server/common/utils/hash"
	"golang.org/x/crypto/bcrypt"
	"net/http"
)

var LoginService = new(loginService)

type loginService struct{}

func (a *loginService) Auth(userDto *model.User) (*model.User, error) {
	if userDto == nil || userDto.UserName == "" || userDto.Password == "" {
		return nil, fmt.Errorf("name or password is empty")
	}
	user, err := repository.UserRepo.GetUserByName(userDto.UserName)
	if err != nil {
		return nil, err
	}
	if err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(userDto.Password)); err != nil {
		return nil, err
	}
	return user, nil
}

func (a *loginService) GetCaptchaId(ctx context.Context, length int) (*dto.LoginCaptcha, error) {
	captchaID := captcha.NewLen(length)
	item := &dto.LoginCaptcha{
		CaptchaID: captchaID,
	}
	return item, nil
}

func (a *loginService) GetCaptchaImage(c *gin.Context, w http.ResponseWriter, captchaID string, width, height int) error {
	err := captcha.WriteImage(w, captchaID, width, height)
	if err != nil {
		if err == captcha.ErrNotFound {
			return errors.ErrNotFound
		}
		return errors.WithStack(err)
	}
	w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
	w.Header().Set("Pragma", "no-cache")
	w.Header().Set("Expires", "0")
	w.Header().Set("Content-Type", "image/png")
	return nil
}

func (a *loginService) DestroyToken(ctx context.Context, tokenString string) error {
	//err := a.Auth.DestroyToken(ctx, tokenString)
	//if err != nil {
	//	return errors.WithStack(err)
	//}
	return nil
}

func (a *loginService) UpdatePassword(c *gin.Context, userID uint64, params dto.UpdatePasswordParam) error {
	user, err := a.getAndCheckUser(userID)
	if err != nil {
		return err
	}
	if hash.SHA1String(params.OldPassword) != user.Password {
		return errors.New400Response("旧密码不正确")
	}
	params.NewPassword = hash.SHA1String(params.NewPassword)
	return repository.UserRepo.UpdatePassword(userID, params.NewPassword)
}

func (a *loginService) getAndCheckUser(userID uint64) (*model.User, error) {
	user, err := repository.UserRepo.SelectById(userID)
	if err != nil {
		return nil, err
	} else if user == nil {
		return nil, errors.ErrNotFound
	} else if user.Status != 1 {
		return nil, errors.ErrUserDisable
	}
	return user, nil
}

func (a *loginService) GetLoginInfo(userID uint64) (*dto.UserLoginInfo, error) {
	user, err := a.getAndCheckUser(userID)
	if err != nil {
		return nil, err
	}

	roleCodes := utils.SplitStringChar(user.RoleCode)
	roleList, err := repo.RoleRepo.QueryByRoleCodes(roleCodes)
	if err != nil {
		return nil, err
	}

	info := &dto.UserLoginInfo{
		UserID:   user.ID,
		UserName: user.UserName,
		RealName: user.RealName,
		Roles:    roleList,
	}

	return info, nil
}
